package com.physics.mps.module.comsol.builder;

import com.physics.mps.module.comsol.vo.CoordinateVo;
import lombok.extern.log4j.Log4j2;

import java.io.File;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author mcsoft
 * @date 2023/10/16 09:38
 * @description comsol java 脚本构建
 */
@Log4j2
public class Builder {



    /**
     * 缩进
     */
    private static final String indent = "    ";

    /**
     * 换行
     */
    private static final String line = "\n";

    /**
     * java 脚本内容
     */
    private final StringBuilder content;


    private final Map<String, AtomicInteger> tagMap;


    /**
     * comsol 工作空间
     */
    public final String workspace;

    public Builder(String dir) {
        this.content = new StringBuilder();
        this.tagMap = new HashMap<>();
        this.workspace = dir;
    }


    /**
     * 开始
     * @param className
     */
    public void start(String className){
        content.append("import com.comsol.model.*;\n");
        content.append("import com.comsol.model.util.*;\n");
        content.append("import com.comsol.model.physics.*;\n");
        content.append("import java.util.*;\n");

        content.append("public class ");
        content.append(className);
        content.append(" {\n");

        buildStaticField();

        buildStaticMethod();

        change(2, 0);

        String run = "    public static Model run() {";
        content.append(run);
    }


    /**
     * 结束
     */
    public void end(){


        change(2, 2);
        content.append("return model;");
        change(2, 1);
        content.append("}");

        change(2, 0);
        String main = "" +
                "    public static void main(String[] args) {\n" +
                "        try {\n" +
                "            run();\n" +
                "            System.out.println(\"COMSOLSUCCESS\");\n" +
                "        } catch (Exception e) {\n" +
                "            StringBuilder exceptionBuilder = new StringBuilder();\n" +
                "            StackTraceElement[] stackTrace = e.getStackTrace();\n" +
                "            for (StackTraceElement element : stackTrace) {\n" +
                "                exceptionBuilder.append(element + \"\\n\");\n" +
                "            }\n" +
                "            e.printStackTrace();\n" +
                "            System.out.println(\"COMSOLERROR:\" + e.getMessage() + \"\\n\" + exceptionBuilder.toString());\n" +
                "            throw new RuntimeException(e.getMessage() + exceptionBuilder.toString());\n" +
                "        }" +
                "    }";
        content.append(main);
        change(2, 0);
        content.append("}");
    }


    /**
     * 静态常量
     */
    public void buildStaticField() {

        change(2, 1);
        content.append("private static final double R = 1E-8;");

        change(2, 1);
        content.append("private static final String BallSelection = \"BallSelection\";");

    }


    /**
     * 静态方法
     */
    public void buildStaticMethod() {


        /**
         * 球选择 createBallSelect
         * @p entityDim     域、边界、边和点
         * @p geom          几何对象
         * @p ballSelectTag 球选择标签
         * @p x y z         坐标点
         */
        {
            change(2, 0);
            content.append("" +
                    "    public static void createBallSelect(int entityDim, GeomSequence geom, String ballSelectTag, double x, double y, double z) {\n" +
                    "        // 创建球选择\n" +
                    "        GeomFeature geomFeature = geom.create(ballSelectTag, BallSelection);\n" +
                    "        // 设置几何实体层\n" +
                    "        geomFeature.set(\"entitydim\", entityDim);\n" +
                    "        // 设置球心坐标\n" +
                    "        geomFeature.set(\"posx\", x);\n" +
                    "        geomFeature.set(\"posy\", y);\n" +
                    "        geomFeature.set(\"posz\", z);\n" +
                    "        // 设置半径\n" +
                    "        geomFeature.set(\"r\", R);\n" +
                    "    }" +
                    "");
        }

    }




    @Override
    public String toString() {
        return content.toString();
    }


    /**
     * 生成文件
     * @param filename
     */
    public void toFile(String filename) {
        File file = new File(filename);
        if (!file.getParentFile().exists()) {
            log.info("toFile mkdir {}", file.getParentFile().mkdirs());
        }
        try (FileWriter fileWriter = new FileWriter(filename);) {
            fileWriter.write(content.toString());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }



    // ~ static

    /**
     * 换一行，缩进两次
     *
     * @return
     */
    public StringBuilder change() {
        return change(1, 2);
    }


    /**
     * 换行缩进
     * @param lineTime
     * @param indentTime
     */
    public StringBuilder change(int lineTime, int indentTime) {
        while (lineTime-- > 0) {
            content.append(line);
        }
        while (indentTime-- > 0) {
            content.append(indent);
        }
        return content;
    }


    /**
     * echo
     * @param msg
     * @return
     */
    public StringBuilder echo(String msg) {
        change(2, 2);
        content.append("//----------------");
        content.append(msg);
        content.append("-----------------//");
        return content;
    }


    /**
     * 赋值
     * @param value
     */
    public StringBuilder value(Object value){
        content.append("\"");
        content.append(value);
        content.append("\"");
        return content;
    }


    /**
     * append
     * @param obj
     * @return
     */
    public StringBuilder append(Object obj) {
        content.append(obj);
        return content;
    }


    /**
     *
     * @param obj
     * @param indent    是否默认缩进
     * @return
     */
    public StringBuilder append(Object obj, boolean indent) {
        if (indent) {
            change();
        }
        content.append(obj);
        return content;
    }



    /**
     * 生成标签
     * @param prefix
     * @return
     */
    public String uniqueTag(String prefix) {
        if (!tagMap.containsKey(prefix)) {
            synchronized (Builder.class) {
                if (!tagMap.containsKey(prefix)) {
                    tagMap.put(prefix, new AtomicInteger(1));
                }
            }
        }
        return prefix + tagMap.get(prefix).getAndIncrement();
    }



    /**
     * 创建球选择
     * @param entityDim
     * @param coordinate
     * @return
     */
    public String createBallSelect(Integer entityDim, CoordinateVo coordinate){
        String ballSelectTag = uniqueTag("ballsel");
        append("createBallSelect(")
                .append(entityDim)
                .append(", geom, ");
        value(ballSelectTag);
        append(", ");
        append(coordinate.getX());
        append(", ");
        append(coordinate.getY());
        append(", ");
        append(coordinate.getZ());
        append(");");
        return ballSelectTag;
    }


}
